﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AdaptiveDeNet.RAND
{
    public class LCG
    {
        private long _prevState;
        private long _seed;

        private const long a = 1664525L; //multiplier
        private const long c = 1013904223L; //increment
        private const long m = 4294967295L; //modulus - 1
        private const long m1 = 4294967296L; //modulus
        private const long b = a - 1;

        public LCG(long seed)
        {
            this._seed = seed;
            this._prevState = seed;
        }

        public LCG()
        {

        }

        public double NextDouble() 
        {
            long num = (a * _prevState + c) % m1;

            this._prevState = num;

            return num / (double)m1;
        }

        public void Skip(int iterNum)
        { 
            // Xn+(k-1)
            //Xn+k = a^k * Xn + ( a^k - 1) * c/b
            int k = iterNum - 1;

            long aExp = this.Lmul(k);

            long prod1 = (aExp * this._prevState) % m1;

            long v1 = (((aExp - 1) * c) ) / b;

            this._prevState = (prod1 + v1) % m1;

        }

        public double[] GetNextSeq(int count)
        {
            double[] seq = new double[count];

            for (int i = 0; i < seq.Length; i++)
            {
                seq[i] = this.NextDouble();    
            }

            return seq;

        }

        public long State
        {
            get { return _prevState; }
            set { _prevState = value; }
        }

        private long Lmul(int exp) 
        {
            long a1 = a % m1;
            long res = 1;

            while (exp > 0)
            {
                if ((exp & 1) == 1)
                {
                    res *= a1;
                    res = res % m1;
                }
                exp /= 2;
                a1 = (a1 * a1) % m1;
            }

            return res;
        }
        
    }
}
